﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YBApproval.IDAL;
using YBApproval.Model;
using System.Data;
using System.Data.Entity;

namespace YBApproval.EFDAL
{
    public class InstanceApprovalDAL : IInstanceApproval
    {
        private YBDbContext db = new YBDbContext();

        public InstanceApproval GetInstanceApproval(int id)
        {
            return db.InstanceApprovals.Where(ia => ia.Id == id).First();
        }

        public List<InstanceApproval> GetInstanceApprovals(string instanceId)
        {
            return db.InstanceApprovals.Where(ia => ia.RecordId == instanceId).ToList();
        }

        /// <summary>
        /// 获取指定ticket，在某一步已通过的票数
        /// </summary>
        /// <param name="instanceId">实例ID</param>
        /// <param name="step">第几步</param>
        /// <returns></returns>
        public int GetApprovalAmountByStep(string instanceId, int step)
        {
            return (from ia in db.InstanceApprovals where ia.RecordId == instanceId && ia.Step == step && ia.IsApproved select ia).Count();
        }

        public int GetNotDenyAmountByStep(string instanceId, int step)
        {
            return (from ia in db.InstanceApprovals where ia.RecordId == instanceId && ia.Step == step && !ia.IsDenied select ia).Count();
        }

        /// <summary>
        /// 获取Node的Approval数据
        /// </summary>
        /// <param name="formId">Form的编号，Form.Id</param>
        /// <param name="nodeOrder">Node的顺序编号，来源于 Node.Order</param>
        /// <returns></returns>
        public List<InstanceApproval> GetInstanceApprovals(int formId, int nodeOrder)
        {
            List<InstanceApproval> result = new List<InstanceApproval>();

            #region Get approval data step by step
            //// TODO: 1st step: get process id
            //List<Form_ProcessSet> fps = db.Form_ProcessSets.Where(p => p.FormId == formId).ToList();
            //int processId = fps.First().ProcessId;

            //// TODO: 2nd step: get node id
            //List<Node> nodes = db.Nodes.Where(p => p.ProcessId == processId && p.Order == nodeOrderId).ToList();
            //int nodeId = nodes.First().Id;

            //// TODO: 3rd step: get approvals which belong to node
            //List<Approval> approvals = db.Approvals.Where(p => p.NodeId == nodeId).ToList();

            //// TODO: 4th step: generate InstanceApproval records based on approval record.
            //InstanceApproval approval;
            //foreach (Approval a in approvals)
            //{
            //    approval = new InstanceApproval();
            //    approval.DefaultApprover = a.Approver;
            //    approval.IsRole = a.IsRole;
            //    approval.NodeId = a.NodeId;

            //    result.Add(approval);
            //}
            #endregion

            // LINQ inner join
            var query = from fp in db.Form_ProcessSets
                        join n in db.Nodes on fp.ProcessId equals n.ProcessId
                        join a in db.Approvals on n.Id equals a.NodeId
                        where fp.FormId == formId && n.Order == nodeOrder
                        select new
                        {
                            Approver = a.ApproverId,
                            IsRole = a.IsRole,
                            NodeId = a.NodeId,
                            NodeType = n.NodeType,
                            NodeOrder = n.Order
                        };
            foreach (var item in query)
            {
                InstanceApproval a = new InstanceApproval();
                a.DefaultApproverId = item.Approver;
                a.IsRole = item.IsRole;
                a.NodeId = item.NodeId;
                a.NodeType = item.NodeType;
                a.NodeOrder = item.NodeOrder;

                result.Add(a);
            }

            return result;
        }

        public void SaveInstanceApproval(InstanceApproval ia)
        {
            db.Entry(ia).State = EntityState.Modified;
            db.SaveChanges();
        }

        public void SaveInstanceApprovals(List<InstanceApproval> values)
        {
            //Guid guid = Guid.NewGuid();
            for (int i = 0; i < values.Count; i++)
            {
                //values[i].RecordId = guid;
                //values[i].Field = null;
                db.InstanceApprovals.Add(values[i]);
            }
            try
            {
                db.SaveChanges();
            }
            catch (Exception)
            {
                throw;
            }
        }

        public int GetCurrentStep(string instanceId)
        {
            return (from ia in db.InstanceApprovals
                    where ia.RecordId == instanceId
                    select ia).Max(ia => ia.Step);
        }

        public List<InstanceApproval> GetInstanceApprovalsForLastStep(string instanceId, int step)
        {
            return (from ia in db.InstanceApprovals
                    where ia.RecordId == instanceId && ia.Step == step
                    select ia).ToList();
        }

        //public void DeleteInstanceApprovals(Guid instanceId)
        //{
        //    List<InstanceApproval> values = db.InstanceApprovals.Where(ia => ia.RecordId == instanceId).ToList();
        //    for (int i = 0; i < values.Count; i++)
        //    {
        //        db.InstanceApprovals.Remove(values[i]);
        //    }
        //    db.SaveChanges();
        //}

        public List<InstanceApproval> GetWorkItems(int userId)
        {
            string roleId = (from u in db.UserProfiles
                             where u.Id == userId
                             select u.RoleId).FirstOrDefault();
            if (string.IsNullOrEmpty(roleId))
            {
                var instApprovals = db.InstanceApprovals.Include(p => p.Record)
                .Where(p => p.Record.IsClosed == false && p.Step == p.Record.Step && (p.IsRole == false && p.DefaultApproverId == userId)
                );
                return instApprovals.ToList();
            }
            else
            {
                List<int> roleIds = new List<int>();
                foreach (var item in roleId.Split(','))
                {
                    roleIds.Add(int.Parse(item));
                }                
                var instApprovals = db.InstanceApprovals.Include(p => p.Record)
                .Where(p => p.Record.IsClosed == false && p.Step == p.Record.Step &&
                    ((p.IsRole && roleIds.Contains(p.DefaultApproverId)) || (p.IsRole == false && p.DefaultApproverId == userId))
                );
                return instApprovals.ToList();
            }
        }

        public List<InstanceApproval> GetApprovedItems(int userId, string recordId = "", int? submitterId = null, string processName = "", DateTime? dtStart = null, DateTime? dtEnd = null)
        {
            return db.InstanceApprovals.Include(p => p.Record.Process).Where(p => p.ApproverId == userId
                && (recordId == "" || p.RecordId == recordId)
                && (submitterId == null || p.Record.SubmitterId == submitterId.Value)
                && (processName == "" || p.Record.Process.Name.ToLower().StartsWith(processName.ToLower()))
                && (dtStart == null || p.Record.SubmitDate > dtStart.Value)
                && (dtEnd == null || p.Record.SubmitDate < dtEnd.Value)).ToList();
        }

        public List<InstanceApproval> GetOpenItems(int userId)
        {
            return db.InstanceApprovals.Include(p => p.Record.CurrentNode).Where(
                p => p.Record.SubmitterId == userId
                    && p.Record.IsClosed == false).ToList();
        }

        public List<InstanceApproval> GetRequestItems(int userId, string recordId = "", int? submitterId = null, string processName = "", DateTime? submitDtStart = null, DateTime? submitDtEnd = null, DateTime? closeDtStart = null, DateTime? closeDtEnd = null)
        {
            return db.InstanceApprovals.Include(p => p.Record.Process).Where(p => p.Record.SubmitterId == userId && p.Record.IsClosed == true
                && (recordId == "" || p.RecordId == recordId)
                && (submitterId == null || p.Record.SubmitterId == submitterId.Value)
                && (processName == "" || p.Record.Process.Name.ToLower().StartsWith(processName.ToLower()))
                && (submitDtStart == null || p.Record.SubmitDate > submitDtStart.Value)
                && (submitDtEnd == null || p.Record.SubmitDate < submitDtEnd.Value)
                && (closeDtStart == null || p.Record.CloseDate > closeDtStart.Value)
                && (closeDtEnd == null || p.Record.CloseDate < closeDtEnd.Value)).ToList();
        }

        public List<Instance> GetDraftItems(int userId)
        {
            return db.Instances.Where(
                p => p.SubmitterId == userId
                    && p.IsSubmitted == false).ToList();
        }

        public void Dispose()
        {
            db.Dispose();
        }
    }
}
